package org.basket.core;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

public class UIManager {
	private static final Logger log = Logger.getLogger(UIManager.class.getName());

	static final Map<Class<?>, Page> pages = new HashMap<Class<?>, Page>(8);

	public static Page getPage(Class<?> clazz) {
		return pages.get(clazz);
	}

	public static void addPage(Class<?> clazz) {
		try {
			final String filename = clazz.getSimpleName() + ".html";
			InputStream is = clazz.getResourceAsStream(filename);
			InputStreamReader isr = new InputStreamReader(is);
			BufferedReader br = new BufferedReader(isr);

			Page page = new Page();
			parse(br, page);
			pages.put(clazz, page);

		} catch (Exception e) {
			log.log(Level.SEVERE, "Cannot generate UI for class: " + clazz.getName(), e);
		}
	}

	/**
	 * separate content by ${___} values.
	 */
	static void parse(Reader br, Page page) {
		page.lines.clear();
		page.context.clear();
		int c = 0;
		char pc = 0;
		StringBuilder expression = new StringBuilder();
		StringBuilder result = new StringBuilder();

		try {
			while (c != -1) {
				pc = (char) c;
				c = br.read();
				if (c == '$') {
					// skip saving and wait till recognized
				} else {
					if (pc == '$') {
						if (c == '{') {
							expression.setLength(0);
							expression.append(pc);
							while (c != -1) {
								expression.append((char) c);
								if (c == '}')
									break;
								c = br.read();
							}

							if (c != '}') {
								// not terminated ${
								result.append(expression);
								page.lines.add(result.toString());
								result.setLength(0);
							} else {
								pc = 0;
								if (result.length() > 0) {
									page.lines.add(result.toString());
									result.setLength(0);
								}
								page.lines.add(expression.toString());
							}
							continue;
						} else {
							// it was only a $ without { after it
							result.append(pc);
						}
					}
					// add current char to the result
					if (c != -1)
						result.append((char) c);
				}
			}

		} catch (IOException e) {
			// reach the end of the stream
		}
		if (result.length() > 0) {
			page.lines.add(result.toString());
		}
	}

	public static class Page {
		List<String> lines = new ArrayList<String>();
		Map<String, String> context = new HashMap<String, String>();

		public void setVar(String var, String value) {
			if (value != null) {
				context.put(var, value);
			} else {
				context.remove(var);
			}
		}

		public void getVar(String var) {
			context.get(var);
		}

		public void render(Writer writer) throws IOException {
			for (final String line : lines) {
				if (line.charAt(0) == '$' && line.charAt(1) == '{' && line.length() > 3) {
					final String varname = line.substring(2, line.length() - 1);
					final String cx = context.get(varname);
					writer.append(cx == null ? varname : cx);
				} else {
					writer.append(line);
				}
			}
		}

	}
}
